use std::fmt::Display;
use std::process::Termination;

use anyerr::context::{AbstractContext, LiteralKeyStringMapContext};
use anyerr::kind::Kind;
use anyerr::AnyError as AnyErrorTemplate; // A predefined context storage

pub use anyerr::kind::DefaultErrorKind as ErrKind; // A predefined error kind.
pub use anyerr::Report;
pub use anyerr::{Intermediate, Overlay}; // Helper traits. // An error reporting utility.

pub type AnyError = AnyErrorTemplate<LiteralKeyStringMapContext, ErrKind>;
pub type AnyResult<T> = Result<T, AnyError>;
pub trait Loggable: Termination + Display {
    fn ignore_kind(self) -> Self;
    fn ignore_context(self) -> Self;
}
impl<C, K> Loggable for Report<C, K>
where
    C: AbstractContext<Entry: Display>,
    K: Kind,
{
    fn ignore_kind(self) -> Self {
        self.kind(false)
    }

    fn ignore_context(self) -> Self {
        self.context(false)
    }
}
pub trait AnyErrorExt {
    fn report(self) -> impl Loggable;
    fn establish(e: anyhow::Error) -> Self;
}
impl AnyErrorExt for AnyError {
    #[inline]
    fn report(self) -> impl Loggable {
        Report::from(self)
            .backtrace(true)
            .pretty(true)
            .kind(true)
            .context(true)
    }

    fn establish(e: anyhow::Error) -> Self {
        AnyError::builder().context("Error", e).build()
    }
}
#[inline]
pub fn log_error(e: impl std::error::Error) {
    log::error!(
        "{}",
        AnyError::builder()
            .context("Error", e)
            .build()
            .report()
            .ignore_kind()
    );
}
